#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <assert.h>
#include "stringmap.h"

#ifndef NULL
#define NULL 0
#endif

/* Load the given list of strings into the key/value map.
 * The key for each string is the numFinalWordsToMatch of the string;
 * the value for each string is the entire string.
 * FIXME: doesn't work for utf-8 strings, since it scans raw chars for /
 */
stringmap_t *stringmap_load(const char *filename, int numFinalWordsToMatch)
{
	stringmap_t *result = calloc(1, sizeof(*result));
	FILE *fp = fopen(filename, "r");
	char buf[2*PATH_MAX];
	int n;

	result->numFinalWordsToMatch = numFinalWordsToMatch;
	if (!fp)
		return NULL;
	n=0;
	while (fgets(buf, sizeof(buf), fp))
		n++;
	result->n = n;
	result->map = malloc(n * sizeof(result->map[0]));

	rewind(fp);
	n=0;
	while (fgets(buf, sizeof(buf), fp)) {
		int pos, w;

		int len = strlen(buf);
		/* strip trailing \n */
		if (len > 0 && buf[len-1] == '\n') {
			buf[len-1] = 0;
			len--;
		}
		/* set pos to the start of the significant part of the string */
		for (pos=len-1, w=0; pos>0; pos--) {
			if (buf[pos] == '/') {
				w++;
				if (w >= numFinalWordsToMatch) {
					pos++;
					break;
				}
			}
		}

		result->map[n].value = strdup(buf);
		result->map[n].key = strdup(buf+pos);
		n++;
	} fclose(fp);
	return result;
}

const char *stringmap_lookup(const stringmap_t *map, const char *string)
{
	int i, w;
	int len = strlen(string);
	int pos;
	for (pos=len-1, w=0; pos>0; pos--) {
		if (string[pos] == '/') {
			w++;
			if (w >= map->numFinalWordsToMatch) {
				pos++;
				break;
			}
		}
	}
	for (i=0; i<map->n; i++) {
		/*printf("Comparing %s and %s\n", map->map[i].key, string+pos);*/
		if (!strcmp(map->map[i].key, string+pos))
			return map->map[i].value;
	}
	return NULL;
}

#if 0

void dumpMap(stringmap_t *sm)
{
	int i;
	printf("map has %d elements, and numFinalWordsToMatch is %d\n", sm->n, sm->numFinalWordsToMatch);
	for (i=0; i < sm->n; i++) {
		printf("row %d: key %s, value %s\n", i, sm->map[i].key, sm->map[i].value);
	}
}

#define verifyMap(sm, a, b) { \
	const char *c = stringmap_lookup(sm, a); \
	if (!b) \
		assert(!c); \
	else { \
		assert(c); \
		assert(!strcmp(b, c)); } }
	
int main(int argc, char **argv)
{
	FILE *fp;
	stringmap_t *sm;

	fp = fopen("stringmap_test.dat", "w");
	fprintf(fp, "/foo/bar/bletch\n");
	fclose(fp);
	sm = stringmap_load("stringmap_test.dat", 1);
	dumpMap(sm);
	verifyMap(sm, "/bar/bletch", "/foo/bar/bletch");
	verifyMap(sm, "bletch", "/foo/bar/bletch");
	verifyMap(sm, "/whatever/bletch", "/foo/bar/bletch");
	verifyMap(sm, "baz", NULL);
	verifyMap(sm, "/foo/bar/bletch", "/foo/bar/bletch");

	fp = fopen("stringmap_test.dat", "w");
	fprintf(fp, "/usr/bin/gcc\n");
	fprintf(fp, "/usr/bin/cc\n");
	fclose(fp);
	sm = stringmap_load("stringmap_test.dat", 1);
	dumpMap(sm);
	verifyMap(sm, "/usr/bin/gcc", "/usr/bin/gcc");
	verifyMap(sm, "/usr/bin/cc", "/usr/bin/cc");
	verifyMap(sm, "gcc", "/usr/bin/gcc");
	verifyMap(sm, "cc", "/usr/bin/cc");
	verifyMap(sm, "g77", NULL);

	fp = fopen("stringmap_test.dat", "w");
	fprintf(fp, "/usr/bin/i686-blah-blah/gcc\n");
	fprintf(fp, "/usr/bin/i386-blah-blah/gcc\n");
	fclose(fp);
	sm = stringmap_load("stringmap_test.dat", 2);
	dumpMap(sm);
	verifyMap(sm, "/usr/bin/i686-blah-blah/gcc",
                      "/usr/bin/i686-blah-blah/gcc");
	verifyMap(sm, "/usr/bin/i386-blah-blah/gcc",
                      "/usr/bin/i386-blah-blah/gcc");
	verifyMap(sm, "i686-blah-blah/gcc", "/usr/bin/i686-blah-blah/gcc");
	verifyMap(sm, "i386-blah-blah/gcc", "/usr/bin/i386-blah-blah/gcc");
	verifyMap(sm, "gcc", NULL);
	verifyMap(sm, "g77", NULL);

        return 0;
}

#endif
